--[=[
 牛牛规则
牌型
52张牌无大小王
1、无牛：没有任意三张牌能加起来成为10的倍数。（注：JQK花牌）
2、有牛：从牛1到牛9，任意三张牌相加是10的倍数，剩余2张牌相加不是10的倍数，相加后取个位数，个位数是几（1-9），就是牛几（1-9）。
3、牛牛：任意三张牌相加是10的倍数，剩余2张牌相加也是10的倍数。
4、四炸：即5张牌中有4张一样的牌，此时无需有牛。
5、五花牛：五花牛的花指的是手上的5张牌全为JQK的特殊牛牛牌型。
6、五小牛 牌类游戏牛牛中五张牌均小于5点，总和小于10点，是牛牛里最大的牌。
牌型比较：
1、单张大小：从大到小为K、Q、J、10、9、8、7、6、5、4、3、2、A。
2、花色大小：从大到小为黑桃、红桃、梅花、方片。
3、牌型大小：从大到小 五花牛、四炸、牛牛、有牛（从牛9到牛1）、没牛。
4、庄闲同牌型时，挑出最大的一张牌进行大小比较，若两方最大牌一样，那么花色进行比较。（特例：四炸时比较四张一样的那张牌）
基本规则
1、分庄家和闲家进行游戏。每个闲家分别和庄家比牌。
2、玩家可以主动上庄，成为本回合的庄家。每回合结束后可重新上庄。
3、玩家可以在四个闲家位置上任意下注。
赔率
低倍场房间：
1、无牛到牛六： 1倍。
2、牛七、牛八、牛九： 2倍。
3、牛牛： 3倍。
4、四炸： 4倍。
5、五花牛： 5倍。
6、五小牛：6倍

]=]

require "luaext"
local Rule = class("Rule")
function  Rule:ctor(args)
	--随机种子
	math.randomseed()
	self.card = {--扑克牌说明，0xBA, (A为花色 3黑桃 2红心 1草花 0方块)，B为点数1-13为A-K 
		0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0,
     	0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xa1, 0xb1, 0xc1, 0xd1,
     	0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 0x82, 0x92, 0xa2, 0xb2, 0xc2, 0xd2,
     	0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, 0x83, 0x93, 0xa3, 0xb3, 0xc3, 0xd3
	}
	--牌型权重基值 无牛，有牛，牛牛，顺子，同花，四花牛，五花牛，葫芦，炸弹，同花顺，五小牛
	self.tbWeight = {wn = 	   		0x00000000,
					 niu1 =	   		0x01000000,  	
					 niu2 = 	   	0x02000000,
					 niu3 =  		0x03000000,	
					 niu4 = 		0x04000000,	
					 niu5 =	   		0x05000000,	
					 niu6 = 	   	0x06000000,	
				   	 niu7 =    		0x07000000, 
				   	 niu8 = 		0x08000000, 
				   	 niu9 = 		0x09000000, 
				   	 niu10 = 		0x0a000000, 
				   	 shunzi =  		0x0b000000,	--顺子
				   	 tonghua =  	0x0c000000,	--同花
				   	 shn = 			0x0d000000,	--四花牛
				   	 whn = 			0x0e000000,	--五花牛
				   	 hulu = 		0x0f000000,	--葫芦
				   	 zhandan = 		0x10000000,	--炸弹
				   	 tonghuashun =  0x11000000,	--同花顺
				   	 wxn = 	   		0x12000000, } --五小牛
	self.tbCard = {} --发牌
	self.tbCardType = {
		[0] = '无牛',
		[1] = '牛一',
		[2] = '牛二',
		[3] = '牛三',
		[4] = '牛四',
		[5] = '牛五',
		[6] = '牛六',
		[7] = '牛七',
		[8] = '牛八',
		[9] = '牛九',
		[10] = '牛牛',
		[11] = '顺子',		--
		[12] = '同花',		--
		[13] = '四花牛',		--
		[14] = '五花牛',		--
		[15] = '葫芦',		--
		[16] = '炸弹',		--
		[17] = '同花顺',		--
		[18] = '五小牛',		--
	}
	self.cardRate = {[0]=1, [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 1, [7] = 1, [8] = 2, [9] = 2, [10] = 3}

	for k, v in pairs(args and args.niuRate or {}) do
		self.cardRate[k] = v or self.cardRate[k]
	end
	for k, v in pairs(args and args.specialCardRate or {}) do
		self.cardRate[k] = v or self.cardRate[k]
	end
end

--洗牌
function Rule:shuffle()	
	for k,v in pairs(self.card) do 
		self.tbCard[k] = v
	end
	table.mix(self.tbCard)
end

--取牌
function Rule:getCard(num)
	local tbRes = {}
	local n = num or 0
	for k,v in pairs(self.tbCard) do 
		if n <= 0 then break end
		if v then 
			n = n-1
			table.insert(tbRes,v)
			self.tbCard[k] = nil
		end
	end
	return tbRes
end

--把牌放到最后
function Rule:pushCard(card)
	table.insert(self.tbCard,card)
end

--5小牛 牌类游戏牛牛中五张牌均小于5点，总和小于10点，是牛牛里最大的牌。
function Rule:isWuxiaoniu(cards)
	local tbCard = table.copy(cards)
	self:sortCard(tbCard)
	
	local totalNum = 0
	for k,v in pairs(tbCard) do 
		if v >= 0x50 then 
			return
		end
		totalNum = totalNum + (v >> 4)
	end
	if totalNum > 10 then 
		return
	end
	local tbRes = {}
	tbRes.cards = tbCard
	tbRes.weight = self.tbWeight.wxn + (totalNum << 8) + tbCard[1]

	return tbRes
end

--是否炸弹， 4张一样的
function Rule:isZhadan(cards)	
	self:sortCard(cards)
	local temp = {}
	for k = 1, #cards -1 do
		if not temp[cards[k] & 0xf0] then
			for j=k+1, #cards  do 
				if (cards[k] & 0xf0) == (cards[j] & 0xf0) then					
					if not temp[cards[k] & 0xf0] then
						temp[cards[k] & 0xf0] = {}
						table.insert(temp[cards[k] & 0xf0], cards[k])				
					end
					table.insert(temp[cards[k] & 0xf0], cards[j])	
				end
			end
		end
	end

	local maxKey --最多相同的
	for k, v in pairs(temp) do
		if not maxKey then
			maxKey = k
		end
		if #temp[maxKey] < #v then
			maxKey = k
		end
	end

	local tbRes
	if maxKey and #temp[maxKey] >= 4 then	
		local tbCard = table.copy(temp[maxKey])
		for k, v in ipairs(cards) do
			local exist = false
			for j, u in ipairs(temp[maxKey]) do
				if v == u then
					exist = true
					break
				end
			end
			if not exist then
				table.insert(tbCard, v)
			end			
		end
		tbRes = {}
		tbRes.card = tbCard
		tbRes.weight = self.tbWeight.zhandan + tbCard[1]
	end
	return tbRes
end

function Rule:isHulu(cards)
	local tbCard = table.copy(cards)
	self:sortCard(cards)
	local temp = {}
	for k = 1, #cards -1 do
		if not temp[cards[k] & 0xf0] then
			for j=k+1, #cards  do 
				if (cards[k] & 0xf0) == (cards[j] & 0xf0) then					
					if not temp[cards[k] & 0xf0] then
						temp[cards[k] & 0xf0] = {}
						table.insert(temp[cards[k] & 0xf0], cards[k])				
					end
					table.insert(temp[cards[k] & 0xf0], cards[j])	
				end
			end
		end
	end

	local piece2, piece3
	for k, v in pairs(temp) do
		if #v == 2 then
			piece2 = k
		end
		if #v == 3 then
			piece3 = k
		end
	end
	local tbRes
	if piece2 and piece3 then	
		local tbCard = table.copy(temp[piece3])		
		for j, u in ipairs(temp[piece2]) do
			table.insert(tbCard, u)
		end
		tbRes = {}
		tbRes.card = tbCard
		tbRes.weight = self.tbWeight.hulu + tbCard[1]
	end
	return tbRes
end

--四花牛 J,J,Q,K, 10
function Rule:isSiHuaNiu(cards)
	local huaCount = 0
	local shiCount = 0
	
	for k, v in ipairs(cards) do
		if v & 0xf0 > 0xa0 then
			huaCount = huaCount + 1
		elseif v & 0xf0 == 0xa0 then
			shiCount = shiCount + 1
		end
	end
	if (huaCount == 4 and shiCount == 1) or (huaCount == 5)  then --五花牛也是一种四花牛
		local tbRes = {}
		local tbCard = table.copy(cards)
		self:sortCard(tbCard)
		tbRes.card = tbCard
		local maxCardWeight = tbCard[1]
		tbRes.weight = self.tbWeight.shn + maxCardWeight
		return tbRes
	end
	return
end

--是否是五花牛
function Rule:isWuHuaNiu(cards)
	local huaCount = 0
	for k, v in ipairs(cards) do
		if v & 0xf0 > 0xa0 then
			huaCount = huaCount + 1
		end
	end
	if huaCount == 5 then
		local tbCard = table.copy(cards)
		self:sortCard(tbCard)
		local tbRes = {}
		tbRes.card = tbCard
		local maxCardWeight = tbCard[1]
		tbRes.weight = self.tbWeight.whn + maxCardWeight
		return tbRes
	end
end

--是否是顺子
function Rule:isShunzi(cards)	
	local tbCard = table.copy(cards)
	self:sortCard(tbCard)
	for i=1, #tbCard -1 do
		if (tbCard[i] & 0xf0) - 0x10 ~= (tbCard[i+1] & 0xf0) then
			return
		end
	end

	local maxCardWeight = tbCard[1]
	local tbRes = {}
	tbRes.card = tbCard
	tbRes.weight = self.tbWeight.shunzi + maxCardWeight
	return tbRes
end

--是否是同花
function Rule:isTonghua(cards)
	local tbCard = table.copy(cards)
	self:sortCard(tbCard)
	local count = 1
	local card = tbCard[1]
	for i=2, #tbCard do
		if (card & 0x0f) ~= (tbCard[i] & 0x0f) then
			return
		end
	end
	local tbRes = {card = tbCard}
	tbRes.weight = self.tbWeight.tonghua + tbCard[1]
	return tbRes
end

--是否是同花顺
function Rule:isTonghuashun(cards)
	local tbCard = table.copy(cards)
	self:sortCard(tbCard)
	if not (self:isTonghua(cards) and self:isShunzi(cards)) then
		return
	end
	local tbRes = {card = tbCard}
	tbRes.weight = self.tbWeight.tonghuashun + tbCard[1]
	return tbRes
end

--是否有牛
function Rule:hasNiu(cards)
	local tbCard = table.copy(cards)
	self:sortCard(tbCard)
	local tbRes = {}
	local tbWeight = self.tbWeight --牌型权重基值
	tbRes.weight = 0 
	local niuji
	local tbc = {
		{1,2,3 ,4,5},
		{1,2,4 ,3,5},
		{1,3,4 ,2,5},
		{2,3,4 ,1,5},
		{1,2,5 ,3,4},
		{1,3,5 ,2,4},
		{2,3,5 ,1,4},
		{1,4,5 ,2,3},
		{2,4,5 ,1,3},
		{3,4,5 ,1,2},
	}
	local a,b,c,d,e
	local temp = {}
	for k,v in pairs(tbc) do 
		a = tbCard[v[1]] & 0xf0
		b = tbCard[v[2]] & 0xf0
		c = tbCard[v[3]] & 0xf0
		d = tbCard[v[4]] & 0xf0
		e = tbCard[v[5]] & 0xf0
		temp = {}
		for i=1,5 do 
			table.insert(temp,tbCard[v[i]])
		end
		if a > 0xa0 then a = 0xa0 end
		if b > 0xa0 then b = 0xa0 end
		if c > 0xa0 then c = 0xa0 end
		if d > 0xa0 then d = 0xa0 end
		if e > 0xa0 then e = 0xa0 end
		if (a+b+c)/0x10%10 == 0 then --有牛
			if (d+e)/0x10%10 == 0 then --牛牛
				tbRes.weight = tbWeight.niu10 + temp[4]
				tbRes.card = temp		
				break
			else
				print(d, e, "niu" .. (d+e)/0x10%10)
				local w = tbWeight["niu" .. math.tointeger((d+e)/0x10%10)] + temp[4]
				if tbRes.weight < w then 
					tbRes.weight = w
					tbRes.card = temp		
					niuji = math.tointeger((d+e)/0x10%10)
					--print("__牛几____________",d,e,niuji)		
				end
			end
		else --无牛
			local w = tbWeight.wn + tbCard[1]
			if (tbRes.weight == 0) or (tbRes.weight < w) then 
				tbRes.weight = w
				tbRes.card = tbCard
			end
		end
	end
	return tbRes
end

--算牛 
function Rule:getNiu(tb)
	--print("1111111___getNiu___card_____________")
	self:printCard(tb)
 	local tbRes = {card={},weight=0} --返回结果
 
	--5小牛
	if self.cardRate[self.tbWeight.wxn] then 
		tbRes = self:isWuxiaoniu(tb)
		if tbRes  then return tbRes end
	end

	--同花顺
	if self.cardRate[self.tbWeight.tonghuashun] then
		tbRes = self:isTonghuashun(tb)
		if tbRes then return tbRes end
	end
	
	--炸
	if self.cardRate[self.tbWeight.zhandan] then
		tbRes = self:isZhadan(tb)
		if tbRes then return tbRes end
	end

	--葫芦
	if self.cardRate[self.tbWeight.hulu] then
		tbRes = self:isHulu(tb)
		if tbRes then return tbRes end
	end

	--五花牛
	if self.cardRate[self.tbWeight.whn] then
		tbRes = self:isWuHuaNiu(tb)
		if tbRes then return tbRes end
	end

	--四花牛
	if self.cardRate[self.tbWeight.shn] then
		tbRes = self:isSiHuaNiu(tb)
		if tbRes then return tbRes end
	end

	--同花
	if self.cardRate[self.tbWeight.tonghua] then
		tbRes = self:isTonghua(tb)
		if tbRes then return tbRes end
	end
	--顺子
	if self.cardRate[self.tbWeight.shunzi] then
		tbRes = self:isShunzi(tb)
		if tbRes then return tbRes end
	end
	
	--牛
	tbRes = self:hasNiu(tb)
	return tbRes
end

function Rule:getCardType(weight)
	return (weight & 0xff000000) / 0x1000000
end

function Rule:getCardTypeText(weight)
	return self.tbCardType[self:getCardType(weight)]
end

--取倍率 
function Rule:getRate(weight)
	local i = (weight&0xff000000) / 0x1000000
	return self.cardRate[i] or 1
end

--降序排序
function Rule:sortCard(cards)
	local _sort = function (first, second) 
		if first > second  then
			return true
		end
		return false
	end
	table.sort(cards, _sort)
end

--输出16进制牌
function Rule:printCard(cards)
	local str = ""
	for k,v in pairs(cards) do 
		str = str..', ' .. string.format("%02x",v)
	end
	print(str)
end
return Rule

